import 'dart:async';

import 'package:flutter/material.dart';
import 'package:boxes_flutter/flutter/slc/router/slc_router.dart';

import '../code/observable_field.dart';
/// @author: slc
/// 自定义的路由导航器
class RouterWidgetVd {
  Function(int, dynamic)? onResult;

  void registerRouterEvent(BuildContext context, RouterVmSub routerVm) {
    //注册页面事件
    routerVm.registerPushPageParamsFunc((pushPageParams) {
      return onPushPageParams(context, pushPageParams);
    });

    routerVm.registerPushReplacementPageParamsFunc((pushPageParams) {
      return onPushReplacementPageParams(context, pushPageParams);
    });

    routerVm.registerPushNamedInfoFunc((slcRouterInfo) {
      return onPushNamedInfoFunc(context, slcRouterInfo);
    });

    routerVm.registerPushReplacementNamedFunc((slcRouterInfo) {
      return onReplacementNamedInfoFunc(context, slcRouterInfo);
    });

    //关闭页面
    routerVm.finishOf.addListener(() {
      dynamic value = (routerVm.finishOf as ObservableField<dynamic>).value;
      if (value != null) {
        Navigator.of(context).pop(value);
        return;
      }
      Navigator.of(context).pop();
    });
  }

  Future<dynamic> onPushPageParams(BuildContext context, pushPageParams) async {
    dynamic result = await context.pushPage(pushPageParams.page,
        settings: pushPageParams.routeSettings);
    onResult?.call(pushPageParams.requestCode, result);
    return result;
  }

  Future<dynamic> onPushReplacementPageParams(
      BuildContext context, pushPageParams) async {
    dynamic result = await context.pushReplacementPage(pushPageParams.page,
        settings: pushPageParams.routeSettings);
    onResult?.call(pushPageParams.requestCode, result);
    return result;
  }

  Future<dynamic> onPushNamedInfoFunc(
      BuildContext context, SlcRouterInfo slcRouterInfo) async {
    dynamic result = await context.pushNamedInfo(slcRouterInfo);
    onResult?.call(slcRouterInfo.requestCode, result);
    return result;
  }

  Future<dynamic> onReplacementNamedInfoFunc(
      BuildContext context, SlcRouterInfo slcRouterInfo) async {
    dynamic result = await context.pushReplacementNamedInfo(slcRouterInfo);
    onResult?.call(slcRouterInfo.requestCode, result);
    return result;
  }
}

///loading dialog的VM
///使用混入引用
///@author sunlunchang

abstract class IRouterVmSub {
  Future<dynamic> pushPage(Widget page,
      {RouteSettings? routeSettings, int requestCode = 0});

  Future<dynamic> pushPageParams(PushPageParams startPageParams);

  Future<dynamic> pushReplacementPage(Widget page,
      {RouteSettings? routeSettings, int requestCode = 0});

  Future<dynamic> pushReplacementPageParams(PushPageParams startPageParams);

  Future<dynamic> pushNamed(String routeName,
      {Map<String, dynamic> arguments = const <String, dynamic>{},
      Object? extra,
      int requestCode = 0});

  Future<dynamic> pushNamedInfo(SlcRouterInfo slcRouterInfo);

  Future<dynamic> pushReplacementNamed(String routeName,
      {Map<String, dynamic> arguments = const <String, dynamic>{},
      Object? extra,
      int requestCode = 0});

  Future<dynamic> pushReplacementNamedInfo(SlcRouterInfo slcRouterInfo);

  finish({dynamic result});
}

/// IRouterVmSub的默认实现
class RouterVmSub implements IRouterVmSub {
  late Future<dynamic> Function(PushPageParams)? _pushPageParamsFunc;

  late Future<dynamic> Function(PushPageParams)? _pushReplacementPageParamsFunc;

  late Future<dynamic> Function(SlcRouterInfo)? _pushNamedInfoFunc;

  late Future<dynamic> Function(SlcRouterInfo)? _pushReplacementNamedFunc;

  final ObservableField<dynamic> _finishOf = ObservableField(single: true);

  ReadObservableField<dynamic> get finishOf => _finishOf;

  void registerPushPageParamsFunc(
      Future<dynamic> Function(PushPageParams)? pushPageParamsFunc) {
    this._pushPageParamsFunc = pushPageParamsFunc;
  }

  void registerPushReplacementPageParamsFunc(
      Future<dynamic> Function(PushPageParams)? pushReplacementPageParamsFunc) {
    this._pushReplacementPageParamsFunc = pushReplacementPageParamsFunc;
  }

  void registerPushNamedInfoFunc(
      Future<dynamic> Function(SlcRouterInfo)? pushNamedInfoFunc) {
    this._pushNamedInfoFunc = pushNamedInfoFunc;
  }

  void registerPushReplacementNamedFunc(
      Future<dynamic> Function(SlcRouterInfo)? pushReplacementNamedFunc) {
    this._pushReplacementNamedFunc = pushReplacementNamedFunc;
  }

  @override
  Future<dynamic> pushPage(Widget page,
      {RouteSettings? routeSettings, int requestCode = 0}) {
    return pushPageParams(PushPageParams(page,
        routeSettings: routeSettings, requestCode: requestCode));
  }

  @override
  Future pushPageParams(PushPageParams startPageParams) {
    if (_pushPageParamsFunc != null) {
      return _pushPageParamsFunc!.call(startPageParams);
    } else {
      throw StateError('pushPageParamsFunc is not initialized');
    }
  }

  @override
  Future<dynamic> pushReplacementPage(Widget page,
      {RouteSettings? routeSettings, int requestCode = 0}) {
    return pushReplacementPageParams(PushPageParams(page,
        routeSettings: routeSettings, requestCode: requestCode));
  }

  @override
  Future pushReplacementPageParams(PushPageParams startPageParams) {
    if (_pushReplacementPageParamsFunc != null) {
      return _pushReplacementPageParamsFunc!.call(startPageParams);
    } else {
      throw StateError('pushReplacementPageParamsFunc is not initialized');
    }
  }

  @override
  Future<dynamic> pushNamed(String routeName,
      {Map<String, dynamic> arguments = const <String, dynamic>{},
      Object? extra,
      int requestCode = 0}) {
    return pushNamedInfo(SlcRouterInfo.fromInfo(routeName,
        arguments: arguments, data: extra, requestCode: requestCode));
  }

  @override
  Future pushNamedInfo(SlcRouterInfo slcRouterInfo) {
    if (_pushNamedInfoFunc != null) {
      return _pushNamedInfoFunc!.call(slcRouterInfo);
    } else {
      throw StateError('pushNamedInfoFunc is not initialized');
    }
  }

  @override
  Future<dynamic> pushReplacementNamed(String routeName,
      {Map<String, dynamic> arguments = const <String, dynamic>{},
      Object? extra,
      int requestCode = 0}) {
    return pushReplacementNamedInfo(SlcRouterInfo.fromInfo(routeName,
        arguments: arguments, data: extra, requestCode: requestCode));
  }

  @override
  Future pushReplacementNamedInfo(SlcRouterInfo slcRouterInfo) {
    if (_pushReplacementNamedFunc != null) {
      return _pushReplacementNamedFunc!.call(slcRouterInfo);
    } else {
      throw StateError('pushNamedInfoFunc is not initialized');
    }
  }

  @override
  finish({dynamic result}) {
    _finishOf.setValueForcedNotify(result);
  }
}
